package me.seawenc.db.checker.dbengine.impl.engines;

import com.alibaba.fastjson.JSONObject;
import me.seawenc.db.checker.dbengine.DsType;
import me.seawenc.db.checker.dbengine.IEngineService;
import me.seawenc.db.checker.bean.FileConfig;
import me.seawenc.db.checker.dbengine.impl.engines.bean.TableDetailBean;
import me.seawenc.db.checker.dbengine.impl.engines.bean.TableNameBean;
import me.seawenc.db.checker.dbengine.impl.utils.SqlActuator;
import me.seawenc.db.checker.helper.ExecTimeCost;
import me.seawenc.db.checker.helper.FileHelper;
import me.seawenc.db.checker.helper.Optionalx;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static me.seawenc.db.checker.dbengine.impl.engines.constant.ConstantFieldName.*;

/**
 * 所有具体实现都必须继承此类，做为模版方法
 */
public abstract class EngineServiceBase implements IEngineService {
    /**
     * sql文件中，对表名的变更代码
     */
    protected  static final String VAR_PARAM_TABLE_NAME = "_table_name_";

    /**
     * sql文件的基础路径
     */
    protected final String sqlsBasePath="/sqls/"+getDsType().lname();

    /**
     * sql执行器
     */
    protected SqlActuator sqlActuator;
    /**
     * 数据源类型
     * @return
     */
    protected abstract DsType getDsType();

    public EngineServiceBase(FileConfig conf) throws Exception {
        sqlActuator =new SqlActuator(conf);
    }


    @Override
    public String findVersion() throws Exception {
        String sql = getVersionSql( getDsType().lname());
        return execSqlTemplete(sql).get(0).getString(VERSION.toString());
    }

    @Override
    public List<TableNameBean> findAllTables() throws Exception {
        String sql = getAllTablesSql(getDsType().lname());
        List<JSONObject> jsonObjects = execSqlTemplete(sql);
        return jsonObjects
                .stream()
                .map(v -> new TableNameBean(v.getString(TAB_NAME.toString()), v.getString(COMMENT.toString())))
                .collect(Collectors.toList());
    }

    @Override
    public TableDetailBean findTableDetail(String tableName) throws Exception {
        ExecTimeCost cost=new ExecTimeCost();
        TableDetailBean detail=null;
        try {
            // 获得表字段信息, hive-spark查出的字段可能会重复，后方需过滤
            detail=execFindTableColumns(tableName,getDsType().lname());
            return detail;
        } finally {
            // 设置执行耗时
            Optionalx.ifPresent(detail,(v)->v.setExecCost(cost.get()));
        }
    }

    @Override
    public List<JSONObject> execSelectSql(String sql) throws Exception {
        return execSqlTemplete(sql);
    }

    /**
     * 获得所查询所有表的sql
     * @return
     */
    protected String getAllTablesSql(String extType){
        return findSql("/select_all_tables.sql",extType);
    }

    /**
     * 获得查询数据库版本sql
     * @return
     */
    protected String getVersionSql(String extType){
        return findSql("/select_version.sql",extType);
    }

    /**
     * 查找sql
     * @param sqlFileName sql文件名
     * @param extType 外部引擎类型，会在对应引擎的子目录中找
     * @return
     */
    protected String findSql(String sqlFileName,String extType){
        String fullFilePath=sqlsBasePath+"/"+extType+sqlFileName;
        if (Optionalx.isPresent(extType)&& FileHelper.resFileExist(fullFilePath)){
            return FileHelper.readResFile(fullFilePath);
        }
        return FileHelper.readResFile(sqlsBasePath+sqlFileName);
    }

    protected String findSql(String sqlFileName,String extType,String tableName){
        return findSql(sqlFileName,extType).replace(VAR_PARAM_TABLE_NAME, Optional.ofNullable(tableName).orElse(""));
    }

    /**
     * 表结构sql
     *
     * @param tableName
     * @return
     */
    protected String getTableDescribeSql(String tableName,String extType){
        return findSql("/select_table_describe.sql",extType,tableName);
    }

    /**
     * 查询表字段
     * @param tableName
     * @return
     * @throws Exception
     */
    protected TableDetailBean execFindTableColumns(String tableName,String extType) throws Exception {
        List<JSONObject> ret = sqlActuator.execQuerySql(getTableDescribeSql(tableName,extType));
        return new TableDetailBean(tableName,ret);
    }

    /**
     * sql执行模版，sql执行完后就关闭数据库连接
     * @param sql
     * @return
     * @throws Exception
     */
    protected List<JSONObject> execSqlTemplete(String sql) throws Exception {
        List<JSONObject> ret = sqlActuator.execQuerySql(sql);
        return ret;
    }

    @Override
    public void closeDbCollection() throws Exception {
        sqlActuator.close();
    }
}
